package com.zyl.blog.CogniSphere.aspect;

import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson2.JSON;
import com.zyl.blog.CogniSphere.mapper.AiApiAccessLogMapper;
import com.zyl.blog.CogniSphere.service.SparkAiSqlService;
import com.zyl.blog.common.domain.ai.bean.AiApiAccessLog;
import com.zyl.blog.common.utils.Extreme.LogUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.time.LocalDateTime;

/**
 * AI接口调用日志AOP切面
 * @version v1.0
 * @ProjectName: Personal_Blog_Server
 * @Package: com.zyl.blog.CogniSphere.aspect
 * @ClassName: AiApiLogAspect
 * @Author FinalFantasy
 * @Date 2025/8/15-11:01
 */
@RequiredArgsConstructor
@Aspect
@Component
public class AiApiLogAspect {

    private final AiApiAccessLogMapper aiApiAccessLogMapper;

    /**
     * 定义切入点：拦截SparkAiSqlService中的方法
     */
    @Pointcut("execution(* com.zyl.blog.CogniSphere.service.SparkAiSqlService.generateCreateTableSql(..))")
    public void aiApiPointcut() {

    }

    /**
     * 环绕通知：记录调用前、调用后信息
     */
    @Around("aiApiPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        /* 初始化日志对象 */
        AiApiAccessLog log = new AiApiAccessLog();

        /* 设置调用前的信息 */
        LocalDateTime invokeTime = LocalDateTime.now();
        String traceId = UUID.randomUUID().toString().replaceAll("-", "");

        /* 0-处理中 */
        log.setTraceId(traceId)
                .setInvokeTime(invokeTime)
                .setModelVersion("spark-lite")
                .setApiType("SQL_GENERATE")
                .setResponseStatus(0);

        /* 获取调用者信息 */
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            /* 可以从请求中获取用户信息或应用标识 */
            /* IP作为调用者标识，实际可替换为用户ID等 */
            log.setCallerId(request.getRemoteAddr());
        } else {
            /* 非Web环境调用 */
            log.setCallerId("system");
        }

        /* 记录请求参数 */
        Object[] args = joinPoint.getArgs();
        if (args != null && args.length > 0) {
            try {
                /* 记录提示词（这里假设第一个参数是TableMeta对象） */
                Object tableMeta = args[0];
                String prompt = SparkAiSqlService.extractPromptFromTableMeta(tableMeta);
                log.setPrompt(prompt);

                /* 记录完整请求参数（脱敏处理） */
                String requestParams = JSON.toJSONString(tableMeta);
                log.setRequestParams(requestParams);

                LogUtil.info("AI接口调用开始，traceId: {}, 调用者: {}, 请求参数: {}",
                        traceId, log.getCallerId(), requestParams);
            } catch (Exception e) {
                LogUtil.error("解析AI接口请求参数失败", e, traceId);
            }
        }

        try {
            /* 执行目标方法 */
            Object result = joinPoint.proceed();

            /* 记录成功响应信息 */
            LocalDateTime responseTime = LocalDateTime.now();

            /* 1-成功 */
            log.setResponseTime(responseTime)
                    .setResponseStatus(1)
                    .setElapsedMs((int) (java.time.Duration.between(invokeTime, responseTime).toMillis()))
                    .setResponseContent(result.toString());

            LogUtil.info("AI接口调用成功，traceId: {}, 耗时: {}ms, 响应结果: {}",
                    traceId, log.getElapsedMs(), result.toString());

            return result;
        } catch (Exception e) {
            /* 记录异常信息 */
            LocalDateTime responseTime = LocalDateTime.now();
            /* 2-失败 */
            log.setResponseTime(responseTime)
                    .setResponseStatus(2)
                    .setElapsedMs((int) (java.time.Duration.between(invokeTime, responseTime).toMillis()))
                    .setErrorCode(e.getClass().getSimpleName())
                    .setErrorMsg(e.getMessage())
                    .setCreateTime(LocalDateTime.now());

            LogUtil.error("AI接口调用失败，traceId: {}, 耗时: {}ms, 错误信息: {}",
                    e, traceId, log.getElapsedMs(), e.getMessage());

            throw e;
        } finally {
            /* 保存日志到数据库 */
            try {
                aiApiAccessLogMapper.insert(log);
                LogUtil.info("AI接口调用日志已保存，traceId: {}, 日志ID: {}", traceId, log.getId());
            } catch (Exception e) {
                LogUtil.error("保存AI接口调用日志失败", e, traceId);
            }
        }
    }
}